#ifndef P3_STATE_MACHINE_H
#define P3_STATE_MACHINE_H

#include "CallbackBase.h"
#include "OSThread.h"
#include "OSMutex.h"
#include "SockStream.h"
#include "MessageHandler.h"
#include "Signal.h"
#include "Command.h"
#include "Status.h"


#include <fstream>
#include <string>

class P3StateMachine : public CallbackBase, private OSThread
{
public:
	enum {
		ConnectionTimeout = 500,	//ms
	};

	//Methods
public:
	P3StateMachine();
	virtual ~P3StateMachine();

private:
	P3StateMachine(const P3StateMachine&);
	P3StateMachine& operator=(const P3StateMachine&);

public:
	// State Manipulation
	bool StartUp(const char* moduleList);
	bool SetConfig();
	bool StartRun();
	bool StopRun();
	bool Shutdown();

	// Properties

	//	system state
	enum SysState{
		Idle = 0,
		WaitingForConnection,
		Publishing,
		Information,	//send the parameters
		Initialization,
		SetConfigIssued,
		Resting,
		RunningInitiated,
		Running,
		Fatal,
		Transition,

		NumStates
	};
	enum SysState SystemState() const
	{ OSMutex::Lock lock( mStateMutex ); return mSystemState; }

	int NumConnections() const
	{ return static_cast<int>( mConnections.size() ); }

	//  Locking.
	void Lock() const
	{ mDataMutex.Acquire(); }
	void Unlock() const
	{ mDataMutex.Release(); }

	bool SetStateValue( const char* name, bool value );

private:
	virtual int OnExecute();	// OSThread interface

	void Init();
	
	void EnterState( enum SysState );
	void PerformTransition(int trasmition);
	void ExecuteTransitionCallbacks(int transmition);
	void BroadcastCommand(const Command&);
	void BroadcastStatus(const Status&);
	void InitializeModules();

	void MaintainDebugLog();
	// Issue a log message.
	void LogMessage( int messageCallbackID, const std::string& );
private:
	enum SysState	mSystemState;
	OSMutex			mStateMutex;
	OSMutex			mDataMutex;
	OSMutex         mP3MessageMutex;

	//mark's protocol
	std::string		mMsgBuff;
public:
	typedef struct ConnectionInfo
	{
		ConnectionInfo()
		:	Name( "" ),
			Address( "" ),
			Status( "no status available" ),
			MessagesSent( 0 ),
			MessagesRecv( 0 )
		{}

		std::string     Name,
						Address,
						Status;
		long			MessagesSent,
						MessagesRecv;
	}ConnectionInfo;
	//--------------------------------------------------- private class CoreConnection
private:
	class CoreConnection;
	friend class CoreConnection;
	class CoreConnection : public MessageHandler
	{
		friend class P3StateMachine;

	public:
		CoreConnection(P3StateMachine&, const std::string& inName, const std::string& inAddress, int inTag );
		~CoreConnection();

		enum Confirmation
		{
			ConfirmInitialized,
			ConfirmRunning,
			ConfirmEndOfRun,
			//ConfirmEndOfStates,
			ConfirmEndOfParameters,

			NumConfirmations
		};

	private:
		void Confirm( Confirmation c )
		{ mConfirmed[c] = true; }
	public:
		void ClearConfirmation( Confirmation c )
		{ mConfirmed[c] = false; }
		bool Confirmed( Confirmation c ) const
		{ return mConfirmed[c]; }

	public:
		void ProcessP3Messages();

		template<typename T> bool PutMessage( const T& t )
		{
			bool result = MessageHandler::PutMessage<T>( mStream, t ).flush();
			if( result )
			{
				OSMutex::Lock lock( mInfoMutex );
				++mInfo.MessagesSent;
			}
			return result;
		}

		const ConnectionInfo Info() const
		{ OSMutex::Lock lock( mInfoMutex ); return mInfo; }

	private:
		virtual bool HandleStatus( std::istream& );
		virtual bool HandleSignal( std::istream& );
		virtual bool HandleCommand( std::istream& );

		void OnAccept();
		void OnDisconnect();

		P3StateMachine&  mrParent;
		std::string      mAddress;
		int              mTag;
		server_tcpsocket mSocket;
		sockstream       mStream;
		bool             mConnected;
		bool             mConfirmed[NumConfirmations];
		ConnectionInfo   mInfo;
		// A mutex to protect info data.
		OSMutex          mInfoMutex;
	};//end of class CoreConnection

	typedef std::vector<CoreConnection*> ConnectionList;
	//--------------------------------------------------- private class CoreConnection

 public:
	ConnectionInfo Info( size_t i ) const;

 private:
	 streamsock::set_of_instances	mSockets;
	 CoreConnection*				mpSourceModule;
	 void ClearConfirmation( CoreConnection::Confirmation c )
	 {
		 for( ConnectionList::iterator i = mConnections.begin(); i != mConnections.end(); ++i )
			 ( *i )->ClearConfirmation( c );
	 }

	 bool Confirmed( CoreConnection::Confirmation c ) const
	 {
		 bool result = true;
		 for( ConnectionList::const_iterator i = mConnections.begin(); i != mConnections.end(); ++i )
			 result &= ( *i )->Confirmed( c );
		 return result;
	 }

	 void CloseConnections()
	 {
		 for( ConnectionList::iterator i = mConnections.begin(); i != mConnections.end(); ++i )
			 delete *i;
		 mConnections.clear();
	 }

	 
private:
	ConnectionList	mConnections;
	std::ofstream   mDebugLog;
};


#endif